Use Dataset created from 02_CLS_Data_Summary_2022_0914_Data_Analysis File

Loading Data

Load Google Sheet

Final_CLS_2022_Study_List_Non_Search_model_file <- read_sheet(
  "https://docs.google.com/spreadsheets/d/1N48rTeq7md0v8w8pG_8XIiuapPHQAeO5WoWIB3eaceI/edit#gid=1449351377",
  sheet = "FinalDataset_2022_Update"
) %>%
  mutate(
    Significant_Spend =
      as.numeric(
        case_when(
          probability_of_lift >= 0.9 ~ 1,
          TRUE ~ 0
        )
      ),
    country = case_when(
      country == "NA" ~ "US",
      TRUE ~ country
    ),
    region_v2 = case_when(
      country == "US" ~ "NA",
      country == "CA" ~ "NA",
      country == "US + CA" ~ "NA",
      TRUE ~ region
    )
  ) %>%
  filter(channel != "Search") %>%
  # filter out studies without reported lifts
  filter(exposed != -1) %>%
  # filter out google pay study
  filter(study_id != "149142217") %>%
  # filter out very negative absolute lifts
  filter(absolute_lift > -1000) %>%
  mutate(
    pa = case_when(
      pa == "Google Ads" ~ "SMB", # Step 1
      pa == "YouTube" & conversion != "Type 256522942 ([MCC] YouTube TV - Web - Trial Start)" ~ "YTMP", # Step 2
      pa == "YouTube Premium" ~ "YTMP", # Step 2
      conversion == "Type 256522942 ([MCC] YouTube TV - Web - Trial Start)" ~ "YouTube TV", # Step 2
      pa == "Cloud" & conversion != "Type 14257803 (Enterprise - Apps - Signup Confirm - Unique)" ~ "Cloud Workspace", # Step 3
      pa == "Cloud" & conversion == "Type 14257803 (Enterprise - Apps - Signup Confirm - Unique)" ~ "Cloud GCP", # Step 3
      pa == "Project Fi" ~ "Google Fi", # Step 4
      pa == "Google Chrome" ~ "Chrome",
      TRUE ~ pa
    )
  ) %>%
  mutate(
    parsed_type = parse_number(conversion),
    grouped_conversion = case_when(
      conversion %in% c("Chromebook Microsite Referral Clicks Q4 2015", "Type 251422729 (Chromebooks Microsite Referral Clicks (Q4 2017))") ~ "Chromebook Referrals",
      conversion %in% c("Desktop Downloads", "Type 11541547 (Desktop Download)") ~
        "Desktop Downloads",
      pa == "Pixel" ~ "Mobile Conversions",
      pa == "DSM" ~ "Non-Mobile Device Conversions",
      conversion == "Type 302982954 (Lena - P Lead)" ~ "Lena P Lead",
      conversion == "Type 288347008 (LENA - B Lead)" ~ "Lena B Lead",
      conversion == "Type 288697653 (LENA - Q Lead)" ~ "Lena Q Lead",
      parsed_type %in% c(181283993, 855508686) ~ "Workspace Free Trial Start",
      parsed_type == 330755641 ~ "Microsite Conversions",
      parsed_type == 14257803 ~ "Enterprise Signups",
      parsed_type == 289680712 ~ "Google(iOs) First Open",
      parsed_type == 256522942 ~ "YouTube TV - Web - Trial Start",
      parsed_type %in% c(452391534, 221497833, 277150074) ~ "Trial Signups Complete",
      TRUE ~ conversion
    ),
    pa = case_when(
      conversion == "Type 288697653 (LENA - Q Lead)" ~ "SMB-QLead",
      TRUE ~ pa
    )
  ) %>%
  filter(absolute_lift > 0)
√ Reading from "Latest CLS Datasets - Internal Only!".
√ Range ''FinalDataset_2022_Update''.
# all.equal(Final_CLS_2022_Study_List_Non_Search_model_file,Final_CLS_2022_Study_List_Non_Search_v3)

Create All Response Curves only normal powers

Folder for all Output and scripts

file.sources <- list.files(path = "RScripts/", pattern = "*.R", full.names = TRUE)
sapply(file.sources, source, .GlobalEnv)
        RScripts/best_ind_function.R RScripts/export_rplots_function.R RScripts/export_rplots_function2.R RScripts/graphing_function.R RScripts/graphing_function2.R
value   ?                            ?                                 ?                                  ?                            ?                            
visible FALSE                        FALSE                             FALSE                              FALSE                        FALSE                        
        RScripts/graphing_function3.R RScripts/graphing_function4.R RScripts/graphing_function4_w_anom.R RScripts/model_wrapper_function.R RScripts/named_group_split.R
value   ?                             ?                             ?                                    ?                                 ?                           
visible FALSE                         FALSE                         FALSE                                FALSE                             FALSE                       
        RScripts/names_function.R RScripts/ridge_lasso_function.R RScripts/ridge_lasso_function2.R RScripts/ridge_lasso_function4.R RScripts/rlm_function.R
value   ?                         ?                               ?                                ?                                ?                      
visible FALSE                     FALSE                           FALSE                            FALSE                            FALSE                  

Check parameters


### powers to try
powers <- seq(0.1, 0.9, by = 0.01)
powers2 <- 1

# For testing purposes
#powers <- seq(0.4, 0.5, by = 0.05)
#powers2 <-seq(0.5,1, by = 0.5)


### Lambda parameters
parameters <- c(
  #  seq(0.1, 2, by =0.1) ,  seq(2, 5, 0.5) ,
  seq(5, 29, 1)
  ,seq(30, 102, 4)
  ,seq(110, 1000, 15)
  ,seq(1000, 10020, 500)
)

### elasticnet parameters
alpha_parameters <- c(seq(0, 1, 0.25))

# For Testing Purposes
#alpha_parameters <- c(seq(1, 1, 1))

Testing Different Model Types

Chrome

Data Readin


start_time <- Sys.time()

Final_CLS_2022_Study_List_Non_Search_model_file_chrome_pre <-
  Final_CLS_2022_Study_List_Non_Search_model_file %>%
  filter(pa == "Chrome") %>%
  mutate(
    id2 = row_number()
  )

df_test <-
  Final_CLS_2022_Study_List_Non_Search_model_file_chrome_pre %>%
  select(
    region_v2, country, channel, tactic,
    cost_spent_on_exposed_group:absolute_lift
  )

iso_chrome <- isolationForest$new(sample_size = nrow(df_test), num_trees = 10000, seed = 1153)

iso_chrome$fit(df_test)
INFO  [00:52:01.660] Building Isolation Forest ...
INFO  [00:52:01.806] done
INFO  [00:52:01.809] Computing depth of terminal nodes ...

Run Model



fits_non_search_chrome <- model_wrapper_function(df = Final_CLS_2022_Study_List_Non_Search_model_file_chrome,poly_ind = 0)

best_ind_non_search_chrome <- 
  lapply(1:length(Final_CLS_2022_Study_List_Non_Search_model_file_chrome), best_ind_function,df = fits_non_search_chrome,
         df2 = Final_CLS_2022_Study_List_Non_Search_model_file_chrome) 

coef_non_search_chrome <- best_ind_non_search_chrome %>% bind_rows #make a matrix of all coefs

best_fit_non_search_chrome <- best_ind_non_search_chrome %>%
  set_names(names_function(Final_CLS_2022_Study_List_Non_Search_model_file_chrome_pre, tactic))  

Create Graph Object

graph_list_chrome <- lapply(1:length(best_fit_non_search_chrome), graphing_function4, df1 = best_fit_non_search_chrome, df2 = Final_CLS_2022_Study_List_Non_Search_model_file_chrome)
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
end_time <- Sys.time()

time_chrome = end_time - start_time

time_chrome
Time difference of 6.4787 mins

Cloud

Data Readin

start_time <- Sys.time()

Final_CLS_2022_Study_List_Non_Search_model_file_cloud_pre <-
  Final_CLS_2022_Study_List_Non_Search_model_file %>%
  filter(pa %in% c("Cloud GCP", "Cloud Workspace")) %>%
  mutate(
    pa = "Cloud",
    pa2 = "Cloud - All Channel"
  ) %>%
  mutate(
    id2 = row_number()
  )

df_test <-
  Final_CLS_2022_Study_List_Non_Search_model_file_cloud_pre %>%
  # select(-study_id, -id2, -region, -scaling_factor, -quarter, -pa, -study_name)
  select(
    region_v2, country, channel, tactic,
    # treatment_user_count:control,
    cost_spent_on_exposed_group:absolute_lift, parsed_type
  )

iso_cloud <- isolationForest$new(sample_size = nrow(df_test), num_trees = 10000, seed = 1153)

iso_cloud$fit(df_test)
INFO  [00:58:30.413] Building Isolation Forest ...
INFO  [00:58:30.490] done
INFO  [00:58:30.493] Computing depth of terminal nodes ...
INFO  [00:58:43.191] done
INFO  [00:58:43.276] Completed growing isolation forest
scores_train <- df_test %>%
  iso_cloud$predict() %>%
  arrange(desc(anomaly_score))

Final_CLS_2022_Study_List_Non_Search_model_file_cloud_pre2 <-
  Final_CLS_2022_Study_List_Non_Search_model_file_cloud_pre %>%
  left_join(scores_train, by = c("id2" = "id"))

Final_CLS_2022_Study_List_Non_Search_model_file_cloud <-
  Final_CLS_2022_Study_List_Non_Search_model_file_cloud_pre2 %>%
  named_group_split(pa2)

Run Model

fits_non_search_cloud <- model_wrapper_function(df = Final_CLS_2022_Study_List_Non_Search_model_file_cloud,poly_ind = 0)

best_ind_non_search_cloud <- 
  lapply(1:length(Final_CLS_2022_Study_List_Non_Search_model_file_cloud), best_ind_function,df = fits_non_search_cloud,
         df2 = Final_CLS_2022_Study_List_Non_Search_model_file_cloud) 

coef_non_search_cloud <- best_ind_non_search_cloud %>% bind_rows #make a matrix of all coefs

best_fit_non_search_cloud <- best_ind_non_search_cloud %>%
  set_names(names_function(Final_CLS_2022_Study_List_Non_Search_model_file_cloud_pre, pa2))  

Create Graph Object

graph_list_cloud <- lapply(1:length(best_fit_non_search_cloud), graphing_function4, df1 = best_fit_non_search_cloud, df2 = Final_CLS_2022_Study_List_Non_Search_model_file_cloud)
Warning: Ignoring unknown aesthetics: text
end_time <- Sys.time()

time_cloud = end_time - start_time

YouTube

Data Readin


start_time <- Sys.time()

Final_CLS_2022_Study_List_Non_Search_model_file_youtube_pre <-
  Final_CLS_2022_Study_List_Non_Search_model_file %>%
  filter(pa %in% c("YouTube TV", "YTMP")) %>%
  mutate(
    pa = "YouTube",
    pa2 = "YouTube"
  ) %>%
  #  filter(absolute_lift < 5000) %>%
  mutate(
    id2 = row_number()
  )

df_test <-
  Final_CLS_2022_Study_List_Non_Search_model_file_youtube_pre %>%
  # select(-study_id, -id2, -region, -scaling_factor, -quarter, -pa, -study_name)
  select(
    region_v2, country, channel, tactic,
    # treatment_user_count:control,
    cost_spent_on_exposed_group:absolute_lift, parsed_type
  )

iso_yt <- isolationForest$new(sample_size = nrow(df_test), num_trees = 10000, seed = 1153)

iso_yt$fit(df_test)
INFO  [01:00:43.101] Building Isolation Forest ...
INFO  [01:00:43.197] done
INFO  [01:00:43.199] Computing depth of terminal nodes ...
INFO  [01:00:56.936] done
INFO  [01:00:57.067] Completed growing isolation forest
scores_train <- df_test %>%
  iso_yt$predict() %>%
  arrange(desc(anomaly_score))

Final_CLS_2022_Study_List_Non_Search_model_file_youtube_pre2 <-
  Final_CLS_2022_Study_List_Non_Search_model_file_youtube_pre %>%
  left_join(scores_train, by = c("id2" = "id")) %>%
  filter(average_depth > 3.89)

Final_CLS_2022_Study_List_Non_Search_model_file_youtube <-
  Final_CLS_2022_Study_List_Non_Search_model_file_youtube_pre2 %>%
  named_group_split(region_v2)

Run Model

fits_non_search_youtube <- model_wrapper_function(df = Final_CLS_2022_Study_List_Non_Search_model_file_youtube,poly_ind = 0)

best_ind_non_search_youtube <- 
  lapply(1:length(Final_CLS_2022_Study_List_Non_Search_model_file_youtube), best_ind_function,df = fits_non_search_youtube,
         df2 = Final_CLS_2022_Study_List_Non_Search_model_file_youtube) 

coef_non_search_youtube <- best_ind_non_search_youtube %>% bind_rows #make a matrix of all coefs

best_fit_non_search_youtube <- best_ind_non_search_youtube %>%
  set_names(names_function(Final_CLS_2022_Study_List_Non_Search_model_file_youtube_pre, pa2))  

Create Graph Object

graph_list_youtube <- lapply(1:length(best_fit_non_search_youtube), graphing_function4, df1 = best_fit_non_search_youtube, df2 = Final_CLS_2022_Study_List_Non_Search_model_file_youtube)
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
end_time <- Sys.time()

time_youtube = end_time - start_time

DSM

Data Readin


start_time <- Sys.time()

Final_CLS_2022_Study_List_Non_Search_model_file_dsm_pre <-
  Final_CLS_2022_Study_List_Non_Search_model_file %>%
  filter(pa == "DSM") %>%
  filter(region_v2 != "APAC") %>%
  # filter(absolute_lift < 1000) # %>%
  # filter(study_id != '6297420') #%>%
  #  filter(study_id !='149161711') %>%
  #  filter(study_id != '148613002') %>%
  # filter(study_id !='3284625') %>%
  #  filter(study_id !='3329131')
  mutate(
    id2 = row_number()
  )

df_test <-
  Final_CLS_2022_Study_List_Non_Search_model_file_dsm_pre %>%
  # select(-study_id, -id2, -region, -scaling_factor, -quarter, -pa, -study_name)
  select(
    region_v2, country, channel, tactic,
    # treatment_user_count:control,
    cost_spent_on_exposed_group:absolute_lift
  )

iso_dsm <- isolationForest$new(sample_size = nrow(df_test), num_trees = 10000, seed = 1152)

iso_dsm$fit(df_test)
INFO  [01:06:25.351] Building Isolation Forest ...
INFO  [01:06:25.508] done
INFO  [01:06:25.511] Computing depth of terminal nodes ...
INFO  [01:06:40.196] done
INFO  [01:06:40.356] Completed growing isolation forest
scores_train <- df_test %>%
  iso_dsm$predict() %>%
  arrange(desc(anomaly_score))

Final_CLS_2022_Study_List_Non_Search_model_file_dsm_pre2 <-
  Final_CLS_2022_Study_List_Non_Search_model_file_dsm_pre %>%
  left_join(scores_train, by = c("id2" = "id")) %>%
  filter(average_depth > 5)

Final_CLS_2022_Study_List_Non_Search_model_file_dsm <-
  Final_CLS_2022_Study_List_Non_Search_model_file_dsm_pre2 %>%
  named_group_split(region_v2, channel)

Run Model

fits_non_search_dsm <- model_wrapper_function(df = Final_CLS_2022_Study_List_Non_Search_model_file_dsm,poly_ind = 0)

best_ind_non_search_dsm <- 
  lapply(1:length(Final_CLS_2022_Study_List_Non_Search_model_file_dsm), best_ind_function,df = fits_non_search_dsm,
         df2 = Final_CLS_2022_Study_List_Non_Search_model_file_dsm)

coef_non_search_dsm <- best_ind_non_search_dsm %>% bind_rows #make a matrix of all coefs

best_fit_non_search_dsm <- best_ind_non_search_dsm %>%
  set_names(names_function(Final_CLS_2022_Study_List_Non_Search_model_file_dsm_pre, region_v2,channel))  

Create Graph Object

graph_list_dsm <- lapply(1:length(best_fit_non_search_dsm), graphing_function4, df1 = best_fit_non_search_dsm, df2 = Final_CLS_2022_Study_List_Non_Search_model_file_dsm)
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
Warning in cor(y_pred, y_actual) : the standard deviation is zero
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
end_time <- Sys.time()

time_dsm = end_time - start_time

Pixel

Data Readin


start_time <- Sys.time()

Final_CLS_2022_Study_List_Non_Search_model_file_pixel_pre <-
  Final_CLS_2022_Study_List_Non_Search_model_file %>%
  filter(pa == "Pixel") %>%
  mutate(
    pa2 = "Pixel - All Channel"
  ) %>%
  #   filter(absolute_lift < 1000)  %>%
  # filter(study_id != '6297420') #%>%
  #  filter(study_id !='149161711') %>%
  #  filter(study_id != '148613002') %>%
  # filter(study_id !='3284625') %>%
  #  filter(study_id !='3329131')
  mutate(
    id2 = row_number()
  )

df_test <-
  Final_CLS_2022_Study_List_Non_Search_model_file_pixel_pre %>%
  # select(-study_id, -id2, -region, -scaling_factor, -quarter, -pa, -study_name)
  select(
    region_v2, country, channel, tactic,
    # treatment_user_count:control,
    cost_spent_on_exposed_group:absolute_lift
  )

iso_pixel <- isolationForest$new(sample_size = nrow(df_test), num_trees = 10000, seed = 1152)

iso_pixel$fit(df_test)
INFO  [01:18:27.306] Building Isolation Forest ...
INFO  [01:18:27.376] done
INFO  [01:18:27.379] Computing depth of terminal nodes ...
INFO  [01:18:40.292] done
INFO  [01:18:40.396] Completed growing isolation forest
scores_train <- df_test %>%
  iso_pixel$predict() %>%
  arrange(desc(anomaly_score))

Final_CLS_2022_Study_List_Non_Search_model_file_pixel_pre2 <-
  Final_CLS_2022_Study_List_Non_Search_model_file_pixel_pre %>%
  left_join(scores_train, by = c("id2" = "id")) %>%
  filter(average_depth > 3.1)

Final_CLS_2022_Study_List_Non_Search_model_file_pixel_pre2


Final_CLS_2022_Study_List_Non_Search_model_file_pixel <-
  Final_CLS_2022_Study_List_Non_Search_model_file_pixel_pre2 %>%
  named_group_split(pa2)

Run Model

fits_non_search_pixel <- model_wrapper_function(df = Final_CLS_2022_Study_List_Non_Search_model_file_pixel,poly_ind = 0)

best_ind_non_search_pixel <- 
  lapply(1:length(Final_CLS_2022_Study_List_Non_Search_model_file_pixel), best_ind_function,df = fits_non_search_pixel,
         df2 = Final_CLS_2022_Study_List_Non_Search_model_file_pixel) 

coef_non_search_pixel <- best_ind_non_search_pixel %>% bind_rows #make a matrix of all coefs

best_fit_non_search_pixel <- best_ind_non_search_pixel %>%
  set_names(names_function(Final_CLS_2022_Study_List_Non_Search_model_file_pixel_pre, pa2))  

Create Graph Object

graph_list_pixel <- lapply(1:length(best_fit_non_search_pixel), graphing_function4, df1 = best_fit_non_search_pixel, df2 = Final_CLS_2022_Study_List_Non_Search_model_file_pixel)
Warning: Ignoring unknown aesthetics: text
end_time <- Sys.time()

time_pixel = end_time - start_time

Fi

Data Readin


start_time <- Sys.time()

Final_CLS_2022_Study_List_Non_Search_model_file_fi_pre <-
  Final_CLS_2022_Study_List_Non_Search_model_file %>%
  filter(pa == "Google Fi") %>%
  mutate(
    pa2 = "Fi - All Channel"
  ) %>%
  #   filter(absolute_lift < 1000)  %>%
  # filter(study_id != '6297420') #%>%
  #  filter(study_id !='149161711') %>%
  #  filter(study_id != '148613002') %>%
  # filter(study_id !='3284625') %>%
  #  filter(study_id !='3329131')
  mutate(
    id2 = row_number()
  )

df_test <-
  Final_CLS_2022_Study_List_Non_Search_model_file_fi_pre %>%
  # select(-study_id, -id2, -region, -scaling_factor, -quarter, -pa, -study_name)
  select(
    region_v2, country, channel, tactic,
    # treatment_user_count:control,
    cost_spent_on_exposed_group:absolute_lift
  )

iso_fi <- isolationForest$new(sample_size = nrow(df_test), num_trees = 10000, seed = 1152)

iso_fi$fit(df_test)
INFO  [01:20:46.871] Building Isolation Forest ...
INFO  [01:20:47.001] done
INFO  [01:20:47.004] Computing depth of terminal nodes ...
INFO  [01:21:01.578] done
INFO  [01:21:01.724] Completed growing isolation forest
scores_train <- df_test %>%
  iso_fi$predict() %>%
  arrange(desc(anomaly_score))

Final_CLS_2022_Study_List_Non_Search_model_file_fi_pre2 <-
  Final_CLS_2022_Study_List_Non_Search_model_file_fi_pre %>%
  left_join(scores_train, by = c("id2" = "id")) %>%
  filter(average_depth > 4.75)

Final_CLS_2022_Study_List_Non_Search_model_file_fi_pre2


Final_CLS_2022_Study_List_Non_Search_model_file_fi <-
  Final_CLS_2022_Study_List_Non_Search_model_file_fi_pre2 %>%
  named_group_split(channel)

Run Model

fits_non_search_fi <- model_wrapper_function(df = Final_CLS_2022_Study_List_Non_Search_model_file_fi,poly_ind = 0)

best_ind_non_search_fi <- 
  lapply(1:length(Final_CLS_2022_Study_List_Non_Search_model_file_fi), best_ind_function,df = fits_non_search_fi,
         df2 = Final_CLS_2022_Study_List_Non_Search_model_file_fi) 

coef_non_search_fi <- best_ind_non_search_fi %>% bind_rows #make a matrix of all coefs

best_fit_non_search_fi <- best_ind_non_search_fi %>%
  set_names(names_function(Final_CLS_2022_Study_List_Non_Search_model_file_fi_pre, pa2))  

Create Graph Object

graph_list_fi <- lapply(1:length(best_fit_non_search_fi), graphing_function4, df1 = best_fit_non_search_fi, df2 = Final_CLS_2022_Study_List_Non_Search_model_file_fi)
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
end_time <- Sys.time()

time_fi = end_time - start_time

SMB - QLeads

Data Readin


start_time <- Sys.time()

Final_CLS_2022_Study_List_Non_Search_model_file_smbq_pre <-
  Final_CLS_2022_Study_List_Non_Search_model_file %>%
  filter(grouped_conversion == 'Lena Q Lead') %>%
  mutate(
    pa2 = "SMB - Q-Lead"
  ) %>%
  #   filter(absolute_lift < 1000)  %>%
  # filter(study_id != '6297420') #%>%
  #  filter(study_id !='149161711') %>%
  #  filter(study_id != '148613002') %>%
  # filter(study_id !='3284625') %>%
  #  filter(study_id !='3329131')
  mutate(
    id2 = row_number()
  )

df_test <-
  Final_CLS_2022_Study_List_Non_Search_model_file_smbq_pre %>%
  # select(-study_id, -id2, -region, -scaling_factor, -quarter, -pa, -study_name)
  select(
    region_v2, country, channel, tactic,
    # treatment_user_count:control,
    cost_spent_on_exposed_group:absolute_lift
  )

iso_smbq <- isolationForest$new(sample_size = nrow(df_test), num_trees = 10000, seed = 1152)

iso_smbq$fit(df_test)
INFO  [01:26:59.441] Building Isolation Forest ...
INFO  [01:26:59.507] done
INFO  [01:26:59.509] Computing depth of terminal nodes ...
INFO  [01:27:12.132] done
INFO  [01:27:12.231] Completed growing isolation forest
scores_train <- df_test %>%
  iso_smbq$predict() %>%
  arrange(desc(anomaly_score))

Final_CLS_2022_Study_List_Non_Search_model_file_smbq_pre2 <-
  Final_CLS_2022_Study_List_Non_Search_model_file_smbq_pre %>%
  left_join(scores_train, by = c("id2" = "id")) %>% 
  filter(average_depth > 1)

Final_CLS_2022_Study_List_Non_Search_model_file_smbq <-
  Final_CLS_2022_Study_List_Non_Search_model_file_smbq_pre2 %>%
  named_group_split(pa2)

Run Model

fits_non_search_smbq <- model_wrapper_function(df = Final_CLS_2022_Study_List_Non_Search_model_file_smbq,poly_ind = 0)

best_ind_non_search_smbq <- 
  lapply(1:length(Final_CLS_2022_Study_List_Non_Search_model_file_smbq), best_ind_function,df = fits_non_search_smbq,
         df2 = Final_CLS_2022_Study_List_Non_Search_model_file_smbq) 

coef_non_search_smbq <- best_ind_non_search_smbq %>% bind_rows #make a matrix of all coefs

best_fit_non_search_smbq <- best_ind_non_search_smbq %>%
  set_names(names_function(Final_CLS_2022_Study_List_Non_Search_model_file_smbq_pre, pa2))  

Create Graph Object

graph_list_smbq <- lapply(1:length(best_fit_non_search_smbq), graphing_function4, df1 = best_fit_non_search_smbq, df2 = Final_CLS_2022_Study_List_Non_Search_model_file_smbq)
Warning: Ignoring unknown aesthetics: text
end_time <- Sys.time()

time_smbq = end_time - start_time

SMB - BLeads

Data Readin


start_time <- Sys.time()

Final_CLS_2022_Study_List_Non_Search_model_file_smbb_pre <-
  Final_CLS_2022_Study_List_Non_Search_model_file %>%
  filter(pa == "SMB" & grouped_conversion == 'Lena B Lead') %>%
  mutate(
    pa2 = "SMB - B-Lead"
  ) %>%
  #   filter(absolute_lift < 1000)  %>%
  # filter(study_id != '6297420') #%>%
  #  filter(study_id !='149161711') %>%
  #  filter(study_id != '148613002') %>%
  # filter(study_id !='3284625') %>%
  #  filter(study_id !='3329131')
  mutate(
    id2 = row_number()
  )

df_test <-
  Final_CLS_2022_Study_List_Non_Search_model_file_smbb_pre %>%
  # select(-study_id, -id2, -region, -scaling_factor, -quarter, -pa, -study_name)
  select(
    region_v2, country, channel, tactic,
    # treatment_user_count:control,
    cost_spent_on_exposed_group:absolute_lift
  )

iso_smbb <- isolationForest$new(sample_size = nrow(df_test), num_trees = 10000, seed = 1152)

iso_smbb$fit(df_test)
INFO  [01:29:18.503] Building Isolation Forest ...
INFO  [01:29:18.644] done
INFO  [01:29:18.647] Computing depth of terminal nodes ...
INFO  [01:29:32.360] done
INFO  [01:29:32.519] Completed growing isolation forest
scores_train <- df_test %>%
  iso_smbb$predict() %>%
  arrange(desc(anomaly_score))

Final_CLS_2022_Study_List_Non_Search_model_file_smbb_pre2 <-
  Final_CLS_2022_Study_List_Non_Search_model_file_smbb_pre %>%
  left_join(scores_train, by = c("id2" = "id")) %>% 
  filter(average_depth > 4)

Final_CLS_2022_Study_List_Non_Search_model_file_smbb <-
  Final_CLS_2022_Study_List_Non_Search_model_file_smbb_pre2 %>%
  named_group_split(channel)

Run Model

fits_non_search_smbb <- model_wrapper_function(df = Final_CLS_2022_Study_List_Non_Search_model_file_smbb,poly_ind = 0)

best_ind_non_search_smbb <- 
  lapply(1:length(Final_CLS_2022_Study_List_Non_Search_model_file_smbb), best_ind_function,df = fits_non_search_smbb,
         df2 = Final_CLS_2022_Study_List_Non_Search_model_file_smbb) 

coef_non_search_smbb <- best_ind_non_search_smbb %>% bind_rows #make a matrix of all coefs

best_fit_non_search_smbb <- best_ind_non_search_smbb %>%
  set_names(names_function(Final_CLS_2022_Study_List_Non_Search_model_file_smbb_pre, channel))  

Create Graph Object

graph_list_smbb <- lapply(1:length(best_fit_non_search_smbb), graphing_function4, df1 = best_fit_non_search_smbb, df2 = Final_CLS_2022_Study_List_Non_Search_model_file_smbb)
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
Warning: Ignoring unknown aesthetics: text
end_time <- Sys.time()

time_smbb = end_time - start_time

Function to refresh all graphs

## Remove two youtube studies from original, add SMB EDA

## for loop of all graph objects

Export all graph lists

graph_names <- mget(ls(pat = 'graph_list_'))
   
df_names <- mget(setdiff(ls(pattern = 'Final_CLS_2022_Study_List_Non_Search_model_file_'), ls(pattern = "pre")))

rm(Final_CLS_2022_Study_List_Non_Search_model_file_Chrome,Final_CLS_2022_Study_List_Non_Search_model_file_Cloud,Final_CLS_2022_Study_List_Non_Search_model_file_YouTube)
Warning in rm(Final_CLS_2022_Study_List_Non_Search_model_file_Chrome, Final_CLS_2022_Study_List_Non_Search_model_file_Cloud,  :
  object 'Final_CLS_2022_Study_List_Non_Search_model_file_Chrome' not found
Warning in rm(Final_CLS_2022_Study_List_Non_Search_model_file_Chrome, Final_CLS_2022_Study_List_Non_Search_model_file_Cloud,  :
  object 'Final_CLS_2022_Study_List_Non_Search_model_file_Cloud' not found
Warning in rm(Final_CLS_2022_Study_List_Non_Search_model_file_Chrome, Final_CLS_2022_Study_List_Non_Search_model_file_Cloud,  :
  object 'Final_CLS_2022_Study_List_Non_Search_model_file_YouTube' not found
lapply(1:length(graph_names),
      function(j) {
lapply(1:length(df_names[[j]]),export_rplots_function2,starting_name = "Non_Search_",folder_name = folder_name,df_list = df_names[[j]],graphing_list = graph_names[j][[1]])
      }
       )
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
Saving 15 x 10 in image
[[1]]
[[1]][[1]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_Chrome_All_Channel.png"

[[1]][[2]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_Chrome_non-REMK.png"

[[1]][[3]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_Chrome_REMK.png"


[[2]]
[[2]][[1]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_Cloud_Cloud_-_All_Channel.png"


[[3]]
[[3]][[1]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_DSM_EMEA__DISCOVERY.png"

[[3]][[2]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_DSM_EMEA__DISPLAY.png"

[[3]][[3]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_DSM_EMEA__YOUTUBE.png"

[[3]][[4]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_DSM_NA__DISCOVERY.png"

[[3]][[5]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_DSM_NA__DISPLAY.png"

[[3]][[6]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_DSM_NA__YOUTUBE.png"


[[4]]
[[4]][[1]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_Google_Fi_DISCOVERY.png"

[[4]][[2]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_Google_Fi_DISPLAY.png"

[[4]][[3]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_Google_Fi_YOUTUBE.png"


[[5]]
[[5]][[1]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_Pixel_Pixel_-_All_Channel.png"


[[6]]
[[6]][[1]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_SMB_DISCOVERY.png"

[[6]][[2]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_SMB_DISPLAY.png"

[[6]][[3]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_SMB_YOUTUBE.png"


[[7]]
[[7]][[1]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_SMB-QLead_SMB_-_Q-Lead.png"


[[8]]
[[8]][[1]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_YouTube_APAC.png"

[[8]][[2]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_YouTube_EMEA.png"

[[8]][[3]]
[1] "Output/outputfiles_2022-10-24_Run1/Non_Search_YouTube_NA.png"

Grid of all Response Curves

Sub Plot Documentation

[[1]]

[[2]]

[[3]]

[[4]]

[[5]]

[[6]]

[[7]]

[[8]]

[[1]]
TableGrob (3 x 1) "arrange": 3 grobs

[[2]]
TableGrob (1 x 1) "arrange": 1 grobs

[[3]]
TableGrob (3 x 2) "arrange": 6 grobs

[[4]]
TableGrob (3 x 1) "arrange": 3 grobs

[[5]]
TableGrob (1 x 1) "arrange": 1 grobs

[[6]]
TableGrob (3 x 1) "arrange": 3 grobs

[[7]]
TableGrob (1 x 1) "arrange": 1 grobs

[[8]]
TableGrob (3 x 1) "arrange": 3 grobs
NA

Coef Matrix

coef.2_matrix <- mget((ls(pat = 'coef_')))

coef.2_matrix %>%  bind_rows()
NA
NA

Graphs with Anomaly Scores

Create all Response Curves - RLM

length(df_names)
[1] 8
rm(grid,cost_p,cost,response,data,power,y,data2,mod,fits.non.search.chrome_RLM)
Warning in rm(grid, cost_p, cost, response, data, power, y, data2, mod,  :
  object 'grid' not found
Warning in rm(grid, cost_p, cost, response, data, power, y, data2, mod,  :
  object 'cost_p' not found
Warning in rm(grid, cost_p, cost, response, data, power, y, data2, mod,  :
  object 'cost' not found
Warning in rm(grid, cost_p, cost, response, data, power, y, data2, mod,  :
  object 'response' not found
Warning in rm(grid, cost_p, cost, response, data, power, y, data2, mod,  :
  object 'data' not found
Warning in rm(grid, cost_p, cost, response, data, power, y, data2, mod,  :
  object 'power' not found
Warning in rm(grid, cost_p, cost, response, data, power, y, data2, mod,  :
  object 'y' not found
Warning in rm(grid, cost_p, cost, response, data, power, y, data2, mod,  :
  object 'data2' not found
Warning in rm(grid, cost_p, cost, response, data, power, y, data2, mod,  :
  object 'mod' not found
LS0tDQp0aXRsZTogIjAzX0NMU19TcGVuZF9SZXNwb25zZV9DdXJ2ZXNfTm9fUG9seSINCmF1dGhvcjogIkVzc2VuY2UgR2xvYmFsIEFkdmFuY2VkIEFuYWx5dGljcyBUZWFtIg0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0Og0KICBodG1sX25vdGVib29rOg0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vDQogICAgdGhlbWU6IGNlcnVsZWFuDQogICAgaGlnaGxpZ2h0OiB6ZW5idXJuDQogICAgZGZfcHJpbnQ6IHBhZ2VkDQotLS0NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpvcHRpb25zKGtuaXRyLnRhYmxlLmZvcm1hdCA9ICJodG1sIikNCm9wdGlvbnMoZGlnaXRzID0gNSkNCm9wdGlvbnMoc2NpcGVuID0gMTAwKQ0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KHRpZHkub3B0cyA9IGxpc3Qod2lkdGguY3V0b2ZmID0gODApLCB0aWR5ID0gVFJVRSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGggPSAxNSkNCmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcuaGVpZ2h0ID0gMTApDQojIGluc3RhbGwucGFja2FnZXMoInBhY21hbiIpDQpsaWJyYXJ5KHBhY21hbikgIyBmb3IgcXVpY2sgbG9hZC9pbnN0YWxsIG9mIHBhY2thZ2VzDQpwX2xvYWQoZHBseXIsIHJlYWRyLCB0aWR5dmVyc2UsIHJldGljdWxhdGUsIGx1YnJpZGF0ZSwgamFuaXRvciwgc3FsZGYsIGdvb2dsZXNoZWV0czQpDQpwX2xvYWQoc2tpbXIsIHNwbGl0c3RhY2tzaGFwZSwgc3RyaW5nciwgcnFkYXRhdGFibGUpDQpwX2xvYWQobW9tZW50cykNCnBfbG9hZChrYWJsZUV4dHJhKQ0KcF9sb2FkKGdncGxvdDIsIHBsb3RseSwgZWNoYXJ0czRyLCBnZ3B1YnIsIGZvcmNhdHMsIHNjYWxlcywgUkNvbG9yQnJld2VyLGdyaWRFeHRyYSkNCnBfbG9hZChnZ3RoZW1lcykNCnBfbG9hZChjYXJldCwgcmVjaXBlcykNCnBfbG9hZChnbG1uZXQpDQpwX2xvYWQoZWxhc3RpY25ldCkNCnBfbG9hZChNZXRyaWNzKQ0KcF9sb2FkKGZhc3REdW1taWVzKQ0KcF9sb2FkKGJyb29tKQ0KcF9sb2FkKGh0bWx3aWRnZXRzKQ0KcF9sb2FkKHNvbGl0dWRlKQ0KcF9sb2FkKG1sYmVuY2gpDQpwX2xvYWQodXdvdCkNCmBgYA0KDQojIFVzZSBEYXRhc2V0IGNyZWF0ZWQgZnJvbSAwMl9DTFNfRGF0YV9TdW1tYXJ5XzIwMjJfMDkxNF9EYXRhX0FuYWx5c2lzIEZpbGUNCg0KIyMgTG9hZGluZyBEYXRhDQoNCiMjIyBMb2FkIEdvb2dsZSBTaGVldA0KDQpgYGB7cn0NCkZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlIDwtIHJlYWRfc2hlZXQoDQogICJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xTjQ4clRlcTdtZDB2OHc4cEdfOFhJaXVhcFBIUUFlTzVXb1dJQjNlYWNlSS9lZGl0I2dpZD0xNDQ5MzUxMzc3IiwNCiAgc2hlZXQgPSAiRmluYWxEYXRhc2V0XzIwMjJfVXBkYXRlIg0KKSAlPiUNCiAgbXV0YXRlKA0KICAgIFNpZ25pZmljYW50X1NwZW5kID0NCiAgICAgIGFzLm51bWVyaWMoDQogICAgICAgIGNhc2Vfd2hlbigNCiAgICAgICAgICBwcm9iYWJpbGl0eV9vZl9saWZ0ID49IDAuOSB+IDEsDQogICAgICAgICAgVFJVRSB+IDANCiAgICAgICAgKQ0KICAgICAgKSwNCiAgICBjb3VudHJ5ID0gY2FzZV93aGVuKA0KICAgICAgY291bnRyeSA9PSAiTkEiIH4gIlVTIiwNCiAgICAgIFRSVUUgfiBjb3VudHJ5DQogICAgKSwNCiAgICByZWdpb25fdjIgPSBjYXNlX3doZW4oDQogICAgICBjb3VudHJ5ID09ICJVUyIgfiAiTkEiLA0KICAgICAgY291bnRyeSA9PSAiQ0EiIH4gIk5BIiwNCiAgICAgIGNvdW50cnkgPT0gIlVTICsgQ0EiIH4gIk5BIiwNCiAgICAgIFRSVUUgfiByZWdpb24NCiAgICApDQogICkgJT4lDQogIGZpbHRlcihjaGFubmVsICE9ICJTZWFyY2giKSAlPiUNCiAgIyBmaWx0ZXIgb3V0IHN0dWRpZXMgd2l0aG91dCByZXBvcnRlZCBsaWZ0cw0KICBmaWx0ZXIoZXhwb3NlZCAhPSAtMSkgJT4lDQogICMgZmlsdGVyIG91dCBnb29nbGUgcGF5IHN0dWR5DQogIGZpbHRlcihzdHVkeV9pZCAhPSAiMTQ5MTQyMjE3IikgJT4lDQogICMgZmlsdGVyIG91dCB2ZXJ5IG5lZ2F0aXZlIGFic29sdXRlIGxpZnRzDQogIGZpbHRlcihhYnNvbHV0ZV9saWZ0ID4gLTEwMDApICU+JQ0KICBtdXRhdGUoDQogICAgcGEgPSBjYXNlX3doZW4oDQogICAgICBwYSA9PSAiR29vZ2xlIEFkcyIgfiAiU01CIiwgIyBTdGVwIDENCiAgICAgIHBhID09ICJZb3VUdWJlIiAmIGNvbnZlcnNpb24gIT0gIlR5cGUgMjU2NTIyOTQyIChbTUNDXSBZb3VUdWJlIFRWIC0gV2ViIC0gVHJpYWwgU3RhcnQpIiB+ICJZVE1QIiwgIyBTdGVwIDINCiAgICAgIHBhID09ICJZb3VUdWJlIFByZW1pdW0iIH4gIllUTVAiLCAjIFN0ZXAgMg0KICAgICAgY29udmVyc2lvbiA9PSAiVHlwZSAyNTY1MjI5NDIgKFtNQ0NdIFlvdVR1YmUgVFYgLSBXZWIgLSBUcmlhbCBTdGFydCkiIH4gIllvdVR1YmUgVFYiLCAjIFN0ZXAgMg0KICAgICAgcGEgPT0gIkNsb3VkIiAmIGNvbnZlcnNpb24gIT0gIlR5cGUgMTQyNTc4MDMgKEVudGVycHJpc2UgLSBBcHBzIC0gU2lnbnVwIENvbmZpcm0gLSBVbmlxdWUpIiB+ICJDbG91ZCBXb3Jrc3BhY2UiLCAjIFN0ZXAgMw0KICAgICAgcGEgPT0gIkNsb3VkIiAmIGNvbnZlcnNpb24gPT0gIlR5cGUgMTQyNTc4MDMgKEVudGVycHJpc2UgLSBBcHBzIC0gU2lnbnVwIENvbmZpcm0gLSBVbmlxdWUpIiB+ICJDbG91ZCBHQ1AiLCAjIFN0ZXAgMw0KICAgICAgcGEgPT0gIlByb2plY3QgRmkiIH4gIkdvb2dsZSBGaSIsICMgU3RlcCA0DQogICAgICBwYSA9PSAiR29vZ2xlIENocm9tZSIgfiAiQ2hyb21lIiwNCiAgICAgIFRSVUUgfiBwYQ0KICAgICkNCiAgKSAlPiUNCiAgbXV0YXRlKA0KICAgIHBhcnNlZF90eXBlID0gcGFyc2VfbnVtYmVyKGNvbnZlcnNpb24pLA0KICAgIGdyb3VwZWRfY29udmVyc2lvbiA9IGNhc2Vfd2hlbigNCiAgICAgIGNvbnZlcnNpb24gJWluJSBjKCJDaHJvbWVib29rIE1pY3Jvc2l0ZSBSZWZlcnJhbCBDbGlja3MgUTQgMjAxNSIsICJUeXBlIDI1MTQyMjcyOSAoQ2hyb21lYm9va3MgTWljcm9zaXRlIFJlZmVycmFsIENsaWNrcyAoUTQgMjAxNykpIikgfiAiQ2hyb21lYm9vayBSZWZlcnJhbHMiLA0KICAgICAgY29udmVyc2lvbiAlaW4lIGMoIkRlc2t0b3AgRG93bmxvYWRzIiwgIlR5cGUgMTE1NDE1NDcgKERlc2t0b3AgRG93bmxvYWQpIikgfg0KICAgICAgICAiRGVza3RvcCBEb3dubG9hZHMiLA0KICAgICAgcGEgPT0gIlBpeGVsIiB+ICJNb2JpbGUgQ29udmVyc2lvbnMiLA0KICAgICAgcGEgPT0gIkRTTSIgfiAiTm9uLU1vYmlsZSBEZXZpY2UgQ29udmVyc2lvbnMiLA0KICAgICAgY29udmVyc2lvbiA9PSAiVHlwZSAzMDI5ODI5NTQgKExlbmEgLSBQIExlYWQpIiB+ICJMZW5hIFAgTGVhZCIsDQogICAgICBjb252ZXJzaW9uID09ICJUeXBlIDI4ODM0NzAwOCAoTEVOQSAtIEIgTGVhZCkiIH4gIkxlbmEgQiBMZWFkIiwNCiAgICAgIGNvbnZlcnNpb24gPT0gIlR5cGUgMjg4Njk3NjUzIChMRU5BIC0gUSBMZWFkKSIgfiAiTGVuYSBRIExlYWQiLA0KICAgICAgcGFyc2VkX3R5cGUgJWluJSBjKDE4MTI4Mzk5MywgODU1NTA4Njg2KSB+ICJXb3Jrc3BhY2UgRnJlZSBUcmlhbCBTdGFydCIsDQogICAgICBwYXJzZWRfdHlwZSA9PSAzMzA3NTU2NDEgfiAiTWljcm9zaXRlIENvbnZlcnNpb25zIiwNCiAgICAgIHBhcnNlZF90eXBlID09IDE0MjU3ODAzIH4gIkVudGVycHJpc2UgU2lnbnVwcyIsDQogICAgICBwYXJzZWRfdHlwZSA9PSAyODk2ODA3MTIgfiAiR29vZ2xlKGlPcykgRmlyc3QgT3BlbiIsDQogICAgICBwYXJzZWRfdHlwZSA9PSAyNTY1MjI5NDIgfiAiWW91VHViZSBUViAtIFdlYiAtIFRyaWFsIFN0YXJ0IiwNCiAgICAgIHBhcnNlZF90eXBlICVpbiUgYyg0NTIzOTE1MzQsIDIyMTQ5NzgzMywgMjc3MTUwMDc0KSB+ICJUcmlhbCBTaWdudXBzIENvbXBsZXRlIiwNCiAgICAgIFRSVUUgfiBjb252ZXJzaW9uDQogICAgKSwNCiAgICBwYSA9IGNhc2Vfd2hlbigNCiAgICAgIGNvbnZlcnNpb24gPT0gIlR5cGUgMjg4Njk3NjUzIChMRU5BIC0gUSBMZWFkKSIgfiAiU01CLVFMZWFkIiwNCiAgICAgIFRSVUUgfiBwYQ0KICAgICkNCiAgKSAlPiUNCiAgZmlsdGVyKGFic29sdXRlX2xpZnQgPiAwKQ0KDQoNCiMgYWxsLmVxdWFsKEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlLEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF92MykNCmBgYA0KDQojIENyZWF0ZSBBbGwgUmVzcG9uc2UgQ3VydmVzIG9ubHkgbm9ybWFsIHBvd2Vycw0KDQojIyBGb2xkZXIgZm9yIGFsbCBPdXRwdXQgYW5kIHNjcmlwdHMNCg0KYGBge3J9DQpmb2xkZXJfbmFtZSA8LSBwYXN0ZTAoIk91dHB1dC8iLCAib3V0cHV0ZmlsZXNfIiwgU3lzLkRhdGUoKSwgIl8iLCAiUnVuMSIsICIvIikNCmRpci5jcmVhdGUoZm9sZGVyX25hbWUpICMgaXQgd2lsbCB0aHJvdyBhIHdhcm5pbmcgaWYgZm9sZGVyIGV4aXN0cw0KDQojIGZpbGUuc291cmNlczIgPC0gbGlzdC5maWxlcyhwYXRoID0gIk91dHB1dC9vdXRwdXRmaWxlc18yMDIyLTEwLTE0X1J1bjEvLyIsIHBhdHRlcm4gPSIuaHRtbHwucG5nIiwgZnVsbC5uYW1lcyA9IFRSVUUpDQpmaWxlLnNvdXJjZXMgPC0gbGlzdC5maWxlcyhwYXRoID0gIlJTY3JpcHRzLyIsIHBhdHRlcm4gPSAiKi5SIiwgZnVsbC5uYW1lcyA9IFRSVUUpDQpzYXBwbHkoZmlsZS5zb3VyY2VzLCBzb3VyY2UsIC5HbG9iYWxFbnYpDQpgYGANCg0KIyMgQ2hlY2sgcGFyYW1ldGVycw0KDQpgYGB7cn0NCg0KIyMjIHBvd2VycyB0byB0cnkNCnBvd2VycyA8LSBzZXEoMC4zLCAwLjQsIGJ5ID0gMC4wNSkNCnBvd2VyczIgPC0gMQ0KDQojIEZvciB0ZXN0aW5nIHB1cnBvc2VzDQojcG93ZXJzIDwtIHNlcSgwLjQsIDAuNSwgYnkgPSAwLjA1KQ0KI3Bvd2VyczIgPC1zZXEoMC41LDEsIGJ5ID0gMC41KQ0KDQoNCiMjIyBMYW1iZGEgcGFyYW1ldGVycw0KcGFyYW1ldGVycyA8LSBjKA0KICAjICBzZXEoMC4xLCAyLCBieSA9MC4xKSAsICBzZXEoMiwgNSwgMC41KSAsDQogIHNlcSg1LCAyOSwgMSkNCiAgLHNlcSgzMCwgMTAyLCA0KQ0KICAsc2VxKDExMCwgMTAwMCwgMTUpDQogICxzZXEoMTAwMCwgMTAwMjAsIDUwMCkNCikNCg0KIyMjIGVsYXN0aWNuZXQgcGFyYW1ldGVycw0KYWxwaGFfcGFyYW1ldGVycyA8LSBjKHNlcSgwLCAxLCAwLjI1KSkNCg0KIyBGb3IgVGVzdGluZyBQdXJwb3Nlcw0KI2FscGhhX3BhcmFtZXRlcnMgPC0gYyhzZXEoMSwgMSwgMSkpDQoNCmBgYA0KDQojIyBUZXN0aW5nIERpZmZlcmVudCBNb2RlbCBUeXBlcw0KDQojIyMgQ2hyb21lDQoNCiMjIyMgRGF0YSBSZWFkaW4NCg0KYGBge3J9DQoNCnN0YXJ0X3RpbWUgPC0gU3lzLnRpbWUoKQ0KDQpGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jaHJvbWVfcHJlIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlICU+JQ0KICBmaWx0ZXIocGEgPT0gIkNocm9tZSIpICU+JQ0KICBtdXRhdGUoDQogICAgaWQyID0gcm93X251bWJlcigpDQogICkNCg0KZGZfdGVzdCA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jaHJvbWVfcHJlICU+JQ0KICBzZWxlY3QoDQogICAgcmVnaW9uX3YyLCBjb3VudHJ5LCBjaGFubmVsLCB0YWN0aWMsDQogICAgY29zdF9zcGVudF9vbl9leHBvc2VkX2dyb3VwOmFic29sdXRlX2xpZnQNCiAgKQ0KDQppc29fY2hyb21lIDwtIGlzb2xhdGlvbkZvcmVzdCRuZXcoc2FtcGxlX3NpemUgPSBucm93KGRmX3Rlc3QpLCBudW1fdHJlZXMgPSAxMDAwMCwgc2VlZCA9IDExNTMpDQoNCmlzb19jaHJvbWUkZml0KGRmX3Rlc3QpDQoNCnNjb3Jlc190cmFpbiA8LSBkZl90ZXN0ICU+JQ0KICBpc29fY2hyb21lJHByZWRpY3QoKSAlPiUNCiAgYXJyYW5nZShkZXNjKGFub21hbHlfc2NvcmUpKQ0KDQpGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jaHJvbWVfcHJlMiA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jaHJvbWVfcHJlICU+JQ0KICBsZWZ0X2pvaW4oc2NvcmVzX3RyYWluLCBieSA9IGMoImlkMiIgPSAiaWQiKSkgJT4lIA0KICBmaWx0ZXIoYXZlcmFnZV9kZXB0aCA+IDMpDQoNCg0KRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfY2hyb21lIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2Nocm9tZV9wcmUyICU+JQ0KICBuYW1lZF9ncm91cF9zcGxpdCh0YWN0aWMpDQpgYGANCg0KIyMjIyBSdW4gTW9kZWwNCg0KYGBge3IsIHdhcm5pbmcgPSBmYWxzZX0NCg0KDQpmaXRzX25vbl9zZWFyY2hfY2hyb21lIDwtIG1vZGVsX3dyYXBwZXJfZnVuY3Rpb24oZGYgPSBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jaHJvbWUscG9seV9pbmQgPSAwKQ0KDQpiZXN0X2luZF9ub25fc2VhcmNoX2Nocm9tZSA8LSANCiAgbGFwcGx5KDE6bGVuZ3RoKEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2Nocm9tZSksIGJlc3RfaW5kX2Z1bmN0aW9uLGRmID0gZml0c19ub25fc2VhcmNoX2Nocm9tZSwNCiAgICAgICAgIGRmMiA9IEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2Nocm9tZSkgDQoNCmNvZWZfbm9uX3NlYXJjaF9jaHJvbWUgPC0gYmVzdF9pbmRfbm9uX3NlYXJjaF9jaHJvbWUgJT4lIGJpbmRfcm93cyAjbWFrZSBhIG1hdHJpeCBvZiBhbGwgY29lZnMNCg0KYmVzdF9maXRfbm9uX3NlYXJjaF9jaHJvbWUgPC0gYmVzdF9pbmRfbm9uX3NlYXJjaF9jaHJvbWUgJT4lDQogIHNldF9uYW1lcyhuYW1lc19mdW5jdGlvbihGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jaHJvbWVfcHJlLCB0YWN0aWMpKSAgDQpgYGANCg0KIyMjIyBDcmVhdGUgR3JhcGggT2JqZWN0DQoNCmBgYHtyfQ0KZ3JhcGhfbGlzdF9jaHJvbWUgPC0gbGFwcGx5KDE6bGVuZ3RoKGJlc3RfZml0X25vbl9zZWFyY2hfY2hyb21lKSwgZ3JhcGhpbmdfZnVuY3Rpb240LCBkZjEgPSBiZXN0X2ZpdF9ub25fc2VhcmNoX2Nocm9tZSwgZGYyID0gRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfY2hyb21lKQ0KYGBgDQoNCmBgYHtyfQ0KZW5kX3RpbWUgPC0gU3lzLnRpbWUoKQ0KDQp0aW1lX2Nocm9tZSA9IGVuZF90aW1lIC0gc3RhcnRfdGltZQ0KDQp0aW1lX2Nocm9tZQ0KYGBgDQoNCiMjIyBDbG91ZA0KDQojIyMjIERhdGEgUmVhZGluDQoNCmBgYHtyfQ0Kc3RhcnRfdGltZSA8LSBTeXMudGltZSgpDQoNCkZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2Nsb3VkX3ByZSA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZSAlPiUNCiAgZmlsdGVyKHBhICVpbiUgYygiQ2xvdWQgR0NQIiwgIkNsb3VkIFdvcmtzcGFjZSIpKSAlPiUNCiAgbXV0YXRlKA0KICAgIHBhID0gIkNsb3VkIiwNCiAgICBwYTIgPSAiQ2xvdWQgLSBBbGwgQ2hhbm5lbCINCiAgKSAlPiUNCiAgbXV0YXRlKA0KICAgIGlkMiA9IHJvd19udW1iZXIoKQ0KICApDQoNCmRmX3Rlc3QgPC0NCiAgRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfY2xvdWRfcHJlICU+JQ0KICAjIHNlbGVjdCgtc3R1ZHlfaWQsIC1pZDIsIC1yZWdpb24sIC1zY2FsaW5nX2ZhY3RvciwgLXF1YXJ0ZXIsIC1wYSwgLXN0dWR5X25hbWUpDQogIHNlbGVjdCgNCiAgICByZWdpb25fdjIsIGNvdW50cnksIGNoYW5uZWwsIHRhY3RpYywNCiAgICAjIHRyZWF0bWVudF91c2VyX2NvdW50OmNvbnRyb2wsDQogICAgY29zdF9zcGVudF9vbl9leHBvc2VkX2dyb3VwOmFic29sdXRlX2xpZnQsIHBhcnNlZF90eXBlDQogICkNCg0KaXNvX2Nsb3VkIDwtIGlzb2xhdGlvbkZvcmVzdCRuZXcoc2FtcGxlX3NpemUgPSBucm93KGRmX3Rlc3QpLCBudW1fdHJlZXMgPSAxMDAwMCwgc2VlZCA9IDExNTMpDQoNCmlzb19jbG91ZCRmaXQoZGZfdGVzdCkNCg0Kc2NvcmVzX3RyYWluIDwtIGRmX3Rlc3QgJT4lDQogIGlzb19jbG91ZCRwcmVkaWN0KCkgJT4lDQogIGFycmFuZ2UoZGVzYyhhbm9tYWx5X3Njb3JlKSkNCg0KRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfY2xvdWRfcHJlMiA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jbG91ZF9wcmUgJT4lDQogIGxlZnRfam9pbihzY29yZXNfdHJhaW4sIGJ5ID0gYygiaWQyIiA9ICJpZCIpKQ0KDQpGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jbG91ZCA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jbG91ZF9wcmUyICU+JQ0KICBuYW1lZF9ncm91cF9zcGxpdChwYTIpDQoNCmBgYA0KDQojIyMjIFJ1biBNb2RlbA0KDQpgYGB7ciwgd2FybmluZyA9IGZhbHNlfQ0KZml0c19ub25fc2VhcmNoX2Nsb3VkIDwtIG1vZGVsX3dyYXBwZXJfZnVuY3Rpb24oZGYgPSBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jbG91ZCxwb2x5X2luZCA9IDApDQoNCmJlc3RfaW5kX25vbl9zZWFyY2hfY2xvdWQgPC0gDQogIGxhcHBseSgxOmxlbmd0aChGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jbG91ZCksIGJlc3RfaW5kX2Z1bmN0aW9uLGRmID0gZml0c19ub25fc2VhcmNoX2Nsb3VkLA0KICAgICAgICAgZGYyID0gRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfY2xvdWQpIA0KDQpjb2VmX25vbl9zZWFyY2hfY2xvdWQgPC0gYmVzdF9pbmRfbm9uX3NlYXJjaF9jbG91ZCAlPiUgYmluZF9yb3dzICNtYWtlIGEgbWF0cml4IG9mIGFsbCBjb2Vmcw0KDQpiZXN0X2ZpdF9ub25fc2VhcmNoX2Nsb3VkIDwtIGJlc3RfaW5kX25vbl9zZWFyY2hfY2xvdWQgJT4lDQogIHNldF9uYW1lcyhuYW1lc19mdW5jdGlvbihGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jbG91ZF9wcmUsIHBhMikpICANCmBgYA0KDQojIyMjIENyZWF0ZSBHcmFwaCBPYmplY3QNCg0KYGBge3J9DQpncmFwaF9saXN0X2Nsb3VkIDwtIGxhcHBseSgxOmxlbmd0aChiZXN0X2ZpdF9ub25fc2VhcmNoX2Nsb3VkKSwgZ3JhcGhpbmdfZnVuY3Rpb240LCBkZjEgPSBiZXN0X2ZpdF9ub25fc2VhcmNoX2Nsb3VkLCBkZjIgPSBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9jbG91ZCkNCmBgYA0KDQoNCmBgYHtyfQ0KZW5kX3RpbWUgPC0gU3lzLnRpbWUoKQ0KDQp0aW1lX2Nsb3VkID0gZW5kX3RpbWUgLSBzdGFydF90aW1lDQpgYGANCg0KIyMjIFlvdVR1YmUNCg0KIyMjIyBEYXRhIFJlYWRpbg0KDQpgYGB7cn0NCg0Kc3RhcnRfdGltZSA8LSBTeXMudGltZSgpDQoNCkZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3lvdXR1YmVfcHJlIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlICU+JQ0KICBmaWx0ZXIocGEgJWluJSBjKCJZb3VUdWJlIFRWIiwgIllUTVAiKSkgJT4lDQogIG11dGF0ZSgNCiAgICBwYSA9ICJZb3VUdWJlIiwNCiAgICBwYTIgPSAiWW91VHViZSINCiAgKSAlPiUNCiAgIyAgZmlsdGVyKGFic29sdXRlX2xpZnQgPCA1MDAwKSAlPiUNCiAgbXV0YXRlKA0KICAgIGlkMiA9IHJvd19udW1iZXIoKQ0KICApDQoNCmRmX3Rlc3QgPC0NCiAgRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfeW91dHViZV9wcmUgJT4lDQogICMgc2VsZWN0KC1zdHVkeV9pZCwgLWlkMiwgLXJlZ2lvbiwgLXNjYWxpbmdfZmFjdG9yLCAtcXVhcnRlciwgLXBhLCAtc3R1ZHlfbmFtZSkNCiAgc2VsZWN0KA0KICAgIHJlZ2lvbl92MiwgY291bnRyeSwgY2hhbm5lbCwgdGFjdGljLA0KICAgICMgdHJlYXRtZW50X3VzZXJfY291bnQ6Y29udHJvbCwNCiAgICBjb3N0X3NwZW50X29uX2V4cG9zZWRfZ3JvdXA6YWJzb2x1dGVfbGlmdCwgcGFyc2VkX3R5cGUNCiAgKQ0KDQppc29feXQgPC0gaXNvbGF0aW9uRm9yZXN0JG5ldyhzYW1wbGVfc2l6ZSA9IG5yb3coZGZfdGVzdCksIG51bV90cmVlcyA9IDEwMDAwLCBzZWVkID0gMTE1MykNCg0KaXNvX3l0JGZpdChkZl90ZXN0KQ0KDQpzY29yZXNfdHJhaW4gPC0gZGZfdGVzdCAlPiUNCiAgaXNvX3l0JHByZWRpY3QoKSAlPiUNCiAgYXJyYW5nZShkZXNjKGFub21hbHlfc2NvcmUpKQ0KDQpGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV95b3V0dWJlX3ByZTIgPC0NCiAgRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfeW91dHViZV9wcmUgJT4lDQogIGxlZnRfam9pbihzY29yZXNfdHJhaW4sIGJ5ID0gYygiaWQyIiA9ICJpZCIpKSAlPiUNCiAgZmlsdGVyKGF2ZXJhZ2VfZGVwdGggPiAzLjg5KQ0KDQpGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV95b3V0dWJlIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3lvdXR1YmVfcHJlMiAlPiUNCiAgbmFtZWRfZ3JvdXBfc3BsaXQocmVnaW9uX3YyKQ0KYGBgDQoNCiMjIyMgUnVuIE1vZGVsDQoNCmBgYHtyLCB3YXJuaW5nID0gZmFsc2V9DQpmaXRzX25vbl9zZWFyY2hfeW91dHViZSA8LSBtb2RlbF93cmFwcGVyX2Z1bmN0aW9uKGRmID0gRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfeW91dHViZSxwb2x5X2luZCA9IDApDQoNCmJlc3RfaW5kX25vbl9zZWFyY2hfeW91dHViZSA8LSANCiAgbGFwcGx5KDE6bGVuZ3RoKEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3lvdXR1YmUpLCBiZXN0X2luZF9mdW5jdGlvbixkZiA9IGZpdHNfbm9uX3NlYXJjaF95b3V0dWJlLA0KICAgICAgICAgZGYyID0gRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfeW91dHViZSkgDQoNCmNvZWZfbm9uX3NlYXJjaF95b3V0dWJlIDwtIGJlc3RfaW5kX25vbl9zZWFyY2hfeW91dHViZSAlPiUgYmluZF9yb3dzICNtYWtlIGEgbWF0cml4IG9mIGFsbCBjb2Vmcw0KDQpiZXN0X2ZpdF9ub25fc2VhcmNoX3lvdXR1YmUgPC0gYmVzdF9pbmRfbm9uX3NlYXJjaF95b3V0dWJlICU+JQ0KICBzZXRfbmFtZXMobmFtZXNfZnVuY3Rpb24oRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfeW91dHViZV9wcmUsIHBhMikpICANCmBgYA0KDQojIyMjIENyZWF0ZSBHcmFwaCBPYmplY3QNCg0KYGBge3J9DQpncmFwaF9saXN0X3lvdXR1YmUgPC0gbGFwcGx5KDE6bGVuZ3RoKGJlc3RfZml0X25vbl9zZWFyY2hfeW91dHViZSksIGdyYXBoaW5nX2Z1bmN0aW9uNCwgZGYxID0gYmVzdF9maXRfbm9uX3NlYXJjaF95b3V0dWJlLCBkZjIgPSBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV95b3V0dWJlKQ0KYGBgDQoNCg0KYGBge3J9DQplbmRfdGltZSA8LSBTeXMudGltZSgpDQoNCnRpbWVfeW91dHViZSA9IGVuZF90aW1lIC0gc3RhcnRfdGltZQ0KYGBgDQoNCg0KIyMjIERTTQ0KDQojIyMjIERhdGEgUmVhZGluDQoNCmBgYHtyfQ0KDQpzdGFydF90aW1lIDwtIFN5cy50aW1lKCkNCg0KRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfZHNtX3ByZSA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZSAlPiUNCiAgZmlsdGVyKHBhID09ICJEU00iKSAlPiUNCiAgZmlsdGVyKHJlZ2lvbl92MiAhPSAiQVBBQyIpICU+JQ0KICAjIGZpbHRlcihhYnNvbHV0ZV9saWZ0IDwgMTAwMCkgIyAlPiUNCiAgIyBmaWx0ZXIoc3R1ZHlfaWQgIT0gJzYyOTc0MjAnKSAjJT4lDQogICMgIGZpbHRlcihzdHVkeV9pZCAhPScxNDkxNjE3MTEnKSAlPiUNCiAgIyAgZmlsdGVyKHN0dWR5X2lkICE9ICcxNDg2MTMwMDInKSAlPiUNCiAgIyBmaWx0ZXIoc3R1ZHlfaWQgIT0nMzI4NDYyNScpICU+JQ0KICAjICBmaWx0ZXIoc3R1ZHlfaWQgIT0nMzMyOTEzMScpDQogIG11dGF0ZSgNCiAgICBpZDIgPSByb3dfbnVtYmVyKCkNCiAgKQ0KDQpkZl90ZXN0IDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2RzbV9wcmUgJT4lDQogICMgc2VsZWN0KC1zdHVkeV9pZCwgLWlkMiwgLXJlZ2lvbiwgLXNjYWxpbmdfZmFjdG9yLCAtcXVhcnRlciwgLXBhLCAtc3R1ZHlfbmFtZSkNCiAgc2VsZWN0KA0KICAgIHJlZ2lvbl92MiwgY291bnRyeSwgY2hhbm5lbCwgdGFjdGljLA0KICAgICMgdHJlYXRtZW50X3VzZXJfY291bnQ6Y29udHJvbCwNCiAgICBjb3N0X3NwZW50X29uX2V4cG9zZWRfZ3JvdXA6YWJzb2x1dGVfbGlmdA0KICApDQoNCmlzb19kc20gPC0gaXNvbGF0aW9uRm9yZXN0JG5ldyhzYW1wbGVfc2l6ZSA9IG5yb3coZGZfdGVzdCksIG51bV90cmVlcyA9IDEwMDAwLCBzZWVkID0gMTE1MikNCg0KaXNvX2RzbSRmaXQoZGZfdGVzdCkNCg0Kc2NvcmVzX3RyYWluIDwtIGRmX3Rlc3QgJT4lDQogIGlzb19kc20kcHJlZGljdCgpICU+JQ0KICBhcnJhbmdlKGRlc2MoYW5vbWFseV9zY29yZSkpDQoNCkZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2RzbV9wcmUyIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2RzbV9wcmUgJT4lDQogIGxlZnRfam9pbihzY29yZXNfdHJhaW4sIGJ5ID0gYygiaWQyIiA9ICJpZCIpKSAlPiUNCiAgZmlsdGVyKGF2ZXJhZ2VfZGVwdGggPiA1KQ0KDQpGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9kc20gPC0NCiAgRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfZHNtX3ByZTIgJT4lDQogIG5hbWVkX2dyb3VwX3NwbGl0KHJlZ2lvbl92MiwgY2hhbm5lbCkNCmBgYA0KDQojIyMjIFJ1biBNb2RlbA0KDQpgYGB7ciwgd2FybmluZyA9IGZhbHNlfQ0KZml0c19ub25fc2VhcmNoX2RzbSA8LSBtb2RlbF93cmFwcGVyX2Z1bmN0aW9uKGRmID0gRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfZHNtLHBvbHlfaW5kID0gMCkNCg0KYmVzdF9pbmRfbm9uX3NlYXJjaF9kc20gPC0gDQogIGxhcHBseSgxOmxlbmd0aChGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9kc20pLCBiZXN0X2luZF9mdW5jdGlvbixkZiA9IGZpdHNfbm9uX3NlYXJjaF9kc20sDQogICAgICAgICBkZjIgPSBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9kc20pDQoNCmNvZWZfbm9uX3NlYXJjaF9kc20gPC0gYmVzdF9pbmRfbm9uX3NlYXJjaF9kc20gJT4lIGJpbmRfcm93cyAjbWFrZSBhIG1hdHJpeCBvZiBhbGwgY29lZnMNCg0KYmVzdF9maXRfbm9uX3NlYXJjaF9kc20gPC0gYmVzdF9pbmRfbm9uX3NlYXJjaF9kc20gJT4lDQogIHNldF9uYW1lcyhuYW1lc19mdW5jdGlvbihGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9kc21fcHJlLCByZWdpb25fdjIsY2hhbm5lbCkpICANCmBgYA0KDQojIyMjIENyZWF0ZSBHcmFwaCBPYmplY3QNCg0KYGBge3J9DQpncmFwaF9saXN0X2RzbSA8LSBsYXBwbHkoMTpsZW5ndGgoYmVzdF9maXRfbm9uX3NlYXJjaF9kc20pLCBncmFwaGluZ19mdW5jdGlvbjQsIGRmMSA9IGJlc3RfZml0X25vbl9zZWFyY2hfZHNtLCBkZjIgPSBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9kc20pDQpgYGANCg0KDQpgYGB7cn0NCmVuZF90aW1lIDwtIFN5cy50aW1lKCkNCg0KdGltZV9kc20gPSBlbmRfdGltZSAtIHN0YXJ0X3RpbWUNCmBgYA0KDQoNCiMjIyBQaXhlbA0KDQojIyMjIERhdGEgUmVhZGluDQoNCmBgYHtyfQ0KDQpzdGFydF90aW1lIDwtIFN5cy50aW1lKCkNCg0KRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfcGl4ZWxfcHJlIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlICU+JQ0KICBmaWx0ZXIocGEgPT0gIlBpeGVsIikgJT4lDQogIG11dGF0ZSgNCiAgICBwYTIgPSAiUGl4ZWwgLSBBbGwgQ2hhbm5lbCINCiAgKSAlPiUNCiAgIyAgIGZpbHRlcihhYnNvbHV0ZV9saWZ0IDwgMTAwMCkgICU+JQ0KICAjIGZpbHRlcihzdHVkeV9pZCAhPSAnNjI5NzQyMCcpICMlPiUNCiAgIyAgZmlsdGVyKHN0dWR5X2lkICE9JzE0OTE2MTcxMScpICU+JQ0KICAjICBmaWx0ZXIoc3R1ZHlfaWQgIT0gJzE0ODYxMzAwMicpICU+JQ0KICAjIGZpbHRlcihzdHVkeV9pZCAhPSczMjg0NjI1JykgJT4lDQogICMgIGZpbHRlcihzdHVkeV9pZCAhPSczMzI5MTMxJykNCiAgbXV0YXRlKA0KICAgIGlkMiA9IHJvd19udW1iZXIoKQ0KICApDQoNCmRmX3Rlc3QgPC0NCiAgRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfcGl4ZWxfcHJlICU+JQ0KICAjIHNlbGVjdCgtc3R1ZHlfaWQsIC1pZDIsIC1yZWdpb24sIC1zY2FsaW5nX2ZhY3RvciwgLXF1YXJ0ZXIsIC1wYSwgLXN0dWR5X25hbWUpDQogIHNlbGVjdCgNCiAgICByZWdpb25fdjIsIGNvdW50cnksIGNoYW5uZWwsIHRhY3RpYywNCiAgICAjIHRyZWF0bWVudF91c2VyX2NvdW50OmNvbnRyb2wsDQogICAgY29zdF9zcGVudF9vbl9leHBvc2VkX2dyb3VwOmFic29sdXRlX2xpZnQNCiAgKQ0KDQppc29fcGl4ZWwgPC0gaXNvbGF0aW9uRm9yZXN0JG5ldyhzYW1wbGVfc2l6ZSA9IG5yb3coZGZfdGVzdCksIG51bV90cmVlcyA9IDEwMDAwLCBzZWVkID0gMTE1MikNCg0KaXNvX3BpeGVsJGZpdChkZl90ZXN0KQ0KDQpzY29yZXNfdHJhaW4gPC0gZGZfdGVzdCAlPiUNCiAgaXNvX3BpeGVsJHByZWRpY3QoKSAlPiUNCiAgYXJyYW5nZShkZXNjKGFub21hbHlfc2NvcmUpKQ0KDQpGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9waXhlbF9wcmUyIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3BpeGVsX3ByZSAlPiUNCiAgbGVmdF9qb2luKHNjb3Jlc190cmFpbiwgYnkgPSBjKCJpZDIiID0gImlkIikpICU+JQ0KICBmaWx0ZXIoYXZlcmFnZV9kZXB0aCA+IDMuMSkNCg0KRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfcGl4ZWxfcHJlMg0KDQoNCkZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3BpeGVsIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3BpeGVsX3ByZTIgJT4lDQogIG5hbWVkX2dyb3VwX3NwbGl0KHBhMikNCmBgYA0KDQojIyMjIFJ1biBNb2RlbA0KDQpgYGB7ciwgd2FybmluZyA9IGZhbHNlfQ0KZml0c19ub25fc2VhcmNoX3BpeGVsIDwtIG1vZGVsX3dyYXBwZXJfZnVuY3Rpb24oZGYgPSBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9waXhlbCxwb2x5X2luZCA9IDApDQoNCmJlc3RfaW5kX25vbl9zZWFyY2hfcGl4ZWwgPC0gDQogIGxhcHBseSgxOmxlbmd0aChGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9waXhlbCksIGJlc3RfaW5kX2Z1bmN0aW9uLGRmID0gZml0c19ub25fc2VhcmNoX3BpeGVsLA0KICAgICAgICAgZGYyID0gRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfcGl4ZWwpIA0KDQpjb2VmX25vbl9zZWFyY2hfcGl4ZWwgPC0gYmVzdF9pbmRfbm9uX3NlYXJjaF9waXhlbCAlPiUgYmluZF9yb3dzICNtYWtlIGEgbWF0cml4IG9mIGFsbCBjb2Vmcw0KDQpiZXN0X2ZpdF9ub25fc2VhcmNoX3BpeGVsIDwtIGJlc3RfaW5kX25vbl9zZWFyY2hfcGl4ZWwgJT4lDQogIHNldF9uYW1lcyhuYW1lc19mdW5jdGlvbihGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9waXhlbF9wcmUsIHBhMikpICANCmBgYA0KDQojIyMjIENyZWF0ZSBHcmFwaCBPYmplY3QNCg0KYGBge3J9DQpncmFwaF9saXN0X3BpeGVsIDwtIGxhcHBseSgxOmxlbmd0aChiZXN0X2ZpdF9ub25fc2VhcmNoX3BpeGVsKSwgZ3JhcGhpbmdfZnVuY3Rpb240LCBkZjEgPSBiZXN0X2ZpdF9ub25fc2VhcmNoX3BpeGVsLCBkZjIgPSBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9waXhlbCkNCmBgYA0KDQoNCmBgYHtyfQ0KZW5kX3RpbWUgPC0gU3lzLnRpbWUoKQ0KDQp0aW1lX3BpeGVsID0gZW5kX3RpbWUgLSBzdGFydF90aW1lDQpgYGANCg0KDQojIyMgRmkNCg0KIyMjIyBEYXRhIFJlYWRpbg0KDQpgYGB7cn0NCg0Kc3RhcnRfdGltZSA8LSBTeXMudGltZSgpDQoNCkZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2ZpX3ByZSA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZSAlPiUNCiAgZmlsdGVyKHBhID09ICJHb29nbGUgRmkiKSAlPiUNCiAgbXV0YXRlKA0KICAgIHBhMiA9ICJGaSAtIEFsbCBDaGFubmVsIg0KICApICU+JQ0KICAjICAgZmlsdGVyKGFic29sdXRlX2xpZnQgPCAxMDAwKSAgJT4lDQogICMgZmlsdGVyKHN0dWR5X2lkICE9ICc2Mjk3NDIwJykgIyU+JQ0KICAjICBmaWx0ZXIoc3R1ZHlfaWQgIT0nMTQ5MTYxNzExJykgJT4lDQogICMgIGZpbHRlcihzdHVkeV9pZCAhPSAnMTQ4NjEzMDAyJykgJT4lDQogICMgZmlsdGVyKHN0dWR5X2lkICE9JzMyODQ2MjUnKSAlPiUNCiAgIyAgZmlsdGVyKHN0dWR5X2lkICE9JzMzMjkxMzEnKQ0KICBtdXRhdGUoDQogICAgaWQyID0gcm93X251bWJlcigpDQogICkNCg0KZGZfdGVzdCA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9maV9wcmUgJT4lDQogICMgc2VsZWN0KC1zdHVkeV9pZCwgLWlkMiwgLXJlZ2lvbiwgLXNjYWxpbmdfZmFjdG9yLCAtcXVhcnRlciwgLXBhLCAtc3R1ZHlfbmFtZSkNCiAgc2VsZWN0KA0KICAgIHJlZ2lvbl92MiwgY291bnRyeSwgY2hhbm5lbCwgdGFjdGljLA0KICAgICMgdHJlYXRtZW50X3VzZXJfY291bnQ6Y29udHJvbCwNCiAgICBjb3N0X3NwZW50X29uX2V4cG9zZWRfZ3JvdXA6YWJzb2x1dGVfbGlmdA0KICApDQoNCmlzb19maSA8LSBpc29sYXRpb25Gb3Jlc3QkbmV3KHNhbXBsZV9zaXplID0gbnJvdyhkZl90ZXN0KSwgbnVtX3RyZWVzID0gMTAwMDAsIHNlZWQgPSAxMTUyKQ0KDQppc29fZmkkZml0KGRmX3Rlc3QpDQoNCnNjb3Jlc190cmFpbiA8LSBkZl90ZXN0ICU+JQ0KICBpc29fZmkkcHJlZGljdCgpICU+JQ0KICBhcnJhbmdlKGRlc2MoYW5vbWFseV9zY29yZSkpDQoNCkZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2ZpX3ByZTIgPC0NCiAgRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfZmlfcHJlICU+JQ0KICBsZWZ0X2pvaW4oc2NvcmVzX3RyYWluLCBieSA9IGMoImlkMiIgPSAiaWQiKSkgJT4lDQogIGZpbHRlcihhdmVyYWdlX2RlcHRoID4gNC43NSkNCg0KRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfZmlfcHJlMg0KDQoNCkZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2ZpIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2ZpX3ByZTIgJT4lDQogIG5hbWVkX2dyb3VwX3NwbGl0KGNoYW5uZWwpDQpgYGANCg0KIyMjIyBSdW4gTW9kZWwNCg0KYGBge3IsIHdhcm5pbmcgPSBmYWxzZX0NCmZpdHNfbm9uX3NlYXJjaF9maSA8LSBtb2RlbF93cmFwcGVyX2Z1bmN0aW9uKGRmID0gRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfZmkscG9seV9pbmQgPSAwKQ0KDQpiZXN0X2luZF9ub25fc2VhcmNoX2ZpIDwtIA0KICBsYXBwbHkoMTpsZW5ndGgoRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfZmkpLCBiZXN0X2luZF9mdW5jdGlvbixkZiA9IGZpdHNfbm9uX3NlYXJjaF9maSwNCiAgICAgICAgIGRmMiA9IEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX2ZpKSANCg0KY29lZl9ub25fc2VhcmNoX2ZpIDwtIGJlc3RfaW5kX25vbl9zZWFyY2hfZmkgJT4lIGJpbmRfcm93cyAjbWFrZSBhIG1hdHJpeCBvZiBhbGwgY29lZnMNCg0KYmVzdF9maXRfbm9uX3NlYXJjaF9maSA8LSBiZXN0X2luZF9ub25fc2VhcmNoX2ZpICU+JQ0KICBzZXRfbmFtZXMobmFtZXNfZnVuY3Rpb24oRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfZmlfcHJlLCBwYTIpKSAgDQpgYGANCg0KIyMjIyBDcmVhdGUgR3JhcGggT2JqZWN0DQoNCmBgYHtyfQ0KZ3JhcGhfbGlzdF9maSA8LSBsYXBwbHkoMTpsZW5ndGgoYmVzdF9maXRfbm9uX3NlYXJjaF9maSksIGdyYXBoaW5nX2Z1bmN0aW9uNCwgZGYxID0gYmVzdF9maXRfbm9uX3NlYXJjaF9maSwgZGYyID0gRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfZmkpDQpgYGANCg0KDQpgYGB7cn0NCmVuZF90aW1lIDwtIFN5cy50aW1lKCkNCg0KdGltZV9maSA9IGVuZF90aW1lIC0gc3RhcnRfdGltZQ0KYGBgDQoNCg0KIyMjIFNNQiAtIFFMZWFkcw0KDQojIyMjIERhdGEgUmVhZGluDQoNCmBgYHtyfQ0KDQpzdGFydF90aW1lIDwtIFN5cy50aW1lKCkNCg0KRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfc21icV9wcmUgPC0NCiAgRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGUgJT4lDQogIGZpbHRlcihncm91cGVkX2NvbnZlcnNpb24gPT0gJ0xlbmEgUSBMZWFkJykgJT4lDQogIG11dGF0ZSgNCiAgICBwYTIgPSAiU01CIC0gUS1MZWFkIg0KICApICU+JQ0KICAjICAgZmlsdGVyKGFic29sdXRlX2xpZnQgPCAxMDAwKSAgJT4lDQogICMgZmlsdGVyKHN0dWR5X2lkICE9ICc2Mjk3NDIwJykgIyU+JQ0KICAjICBmaWx0ZXIoc3R1ZHlfaWQgIT0nMTQ5MTYxNzExJykgJT4lDQogICMgIGZpbHRlcihzdHVkeV9pZCAhPSAnMTQ4NjEzMDAyJykgJT4lDQogICMgZmlsdGVyKHN0dWR5X2lkICE9JzMyODQ2MjUnKSAlPiUNCiAgIyAgZmlsdGVyKHN0dWR5X2lkICE9JzMzMjkxMzEnKQ0KICBtdXRhdGUoDQogICAgaWQyID0gcm93X251bWJlcigpDQogICkNCg0KZGZfdGVzdCA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9zbWJxX3ByZSAlPiUNCiAgIyBzZWxlY3QoLXN0dWR5X2lkLCAtaWQyLCAtcmVnaW9uLCAtc2NhbGluZ19mYWN0b3IsIC1xdWFydGVyLCAtcGEsIC1zdHVkeV9uYW1lKQ0KICBzZWxlY3QoDQogICAgcmVnaW9uX3YyLCBjb3VudHJ5LCBjaGFubmVsLCB0YWN0aWMsDQogICAgIyB0cmVhdG1lbnRfdXNlcl9jb3VudDpjb250cm9sLA0KICAgIGNvc3Rfc3BlbnRfb25fZXhwb3NlZF9ncm91cDphYnNvbHV0ZV9saWZ0DQogICkNCg0KaXNvX3NtYnEgPC0gaXNvbGF0aW9uRm9yZXN0JG5ldyhzYW1wbGVfc2l6ZSA9IG5yb3coZGZfdGVzdCksIG51bV90cmVlcyA9IDEwMDAwLCBzZWVkID0gMTE1MikNCg0KaXNvX3NtYnEkZml0KGRmX3Rlc3QpDQoNCnNjb3Jlc190cmFpbiA8LSBkZl90ZXN0ICU+JQ0KICBpc29fc21icSRwcmVkaWN0KCkgJT4lDQogIGFycmFuZ2UoZGVzYyhhbm9tYWx5X3Njb3JlKSkNCg0KRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfc21icV9wcmUyIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3NtYnFfcHJlICU+JQ0KICBsZWZ0X2pvaW4oc2NvcmVzX3RyYWluLCBieSA9IGMoImlkMiIgPSAiaWQiKSkgJT4lIA0KICBmaWx0ZXIoYXZlcmFnZV9kZXB0aCA+IDEpDQoNCkZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3NtYnEgPC0NCiAgRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfc21icV9wcmUyICU+JQ0KICBuYW1lZF9ncm91cF9zcGxpdChwYTIpDQpgYGANCg0KIyMjIyBSdW4gTW9kZWwNCg0KYGBge3IsIHdhcm5pbmcgPSBmYWxzZX0NCmZpdHNfbm9uX3NlYXJjaF9zbWJxIDwtIG1vZGVsX3dyYXBwZXJfZnVuY3Rpb24oZGYgPSBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9zbWJxLHBvbHlfaW5kID0gMCkNCg0KYmVzdF9pbmRfbm9uX3NlYXJjaF9zbWJxIDwtIA0KICBsYXBwbHkoMTpsZW5ndGgoRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfc21icSksIGJlc3RfaW5kX2Z1bmN0aW9uLGRmID0gZml0c19ub25fc2VhcmNoX3NtYnEsDQogICAgICAgICBkZjIgPSBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9zbWJxKSANCg0KY29lZl9ub25fc2VhcmNoX3NtYnEgPC0gYmVzdF9pbmRfbm9uX3NlYXJjaF9zbWJxICU+JSBiaW5kX3Jvd3MgI21ha2UgYSBtYXRyaXggb2YgYWxsIGNvZWZzDQoNCmJlc3RfZml0X25vbl9zZWFyY2hfc21icSA8LSBiZXN0X2luZF9ub25fc2VhcmNoX3NtYnEgJT4lDQogIHNldF9uYW1lcyhuYW1lc19mdW5jdGlvbihGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9zbWJxX3ByZSwgcGEyKSkgIA0KYGBgDQoNCiMjIyMgQ3JlYXRlIEdyYXBoIE9iamVjdA0KDQpgYGB7cn0NCmdyYXBoX2xpc3Rfc21icSA8LSBsYXBwbHkoMTpsZW5ndGgoYmVzdF9maXRfbm9uX3NlYXJjaF9zbWJxKSwgZ3JhcGhpbmdfZnVuY3Rpb240LCBkZjEgPSBiZXN0X2ZpdF9ub25fc2VhcmNoX3NtYnEsIGRmMiA9IEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3NtYnEpDQpgYGANCg0KDQpgYGB7cn0NCmVuZF90aW1lIDwtIFN5cy50aW1lKCkNCg0KdGltZV9zbWJxID0gZW5kX3RpbWUgLSBzdGFydF90aW1lDQpgYGANCg0KDQojIyMgU01CIC0gQkxlYWRzDQoNCiMjIyMgRGF0YSBSZWFkaW4NCg0KYGBge3J9DQoNCnN0YXJ0X3RpbWUgPC0gU3lzLnRpbWUoKQ0KDQpGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9zbWJiX3ByZSA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZSAlPiUNCiAgZmlsdGVyKHBhID09ICJTTUIiICYgZ3JvdXBlZF9jb252ZXJzaW9uID09ICdMZW5hIEIgTGVhZCcpICU+JQ0KICBtdXRhdGUoDQogICAgcGEyID0gIlNNQiAtIEItTGVhZCINCiAgKSAlPiUNCiAgIyAgIGZpbHRlcihhYnNvbHV0ZV9saWZ0IDwgMTAwMCkgICU+JQ0KICAjIGZpbHRlcihzdHVkeV9pZCAhPSAnNjI5NzQyMCcpICMlPiUNCiAgIyAgZmlsdGVyKHN0dWR5X2lkICE9JzE0OTE2MTcxMScpICU+JQ0KICAjICBmaWx0ZXIoc3R1ZHlfaWQgIT0gJzE0ODYxMzAwMicpICU+JQ0KICAjIGZpbHRlcihzdHVkeV9pZCAhPSczMjg0NjI1JykgJT4lDQogICMgIGZpbHRlcihzdHVkeV9pZCAhPSczMzI5MTMxJykNCiAgbXV0YXRlKA0KICAgIGlkMiA9IHJvd19udW1iZXIoKQ0KICApDQoNCmRmX3Rlc3QgPC0NCiAgRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfc21iYl9wcmUgJT4lDQogICMgc2VsZWN0KC1zdHVkeV9pZCwgLWlkMiwgLXJlZ2lvbiwgLXNjYWxpbmdfZmFjdG9yLCAtcXVhcnRlciwgLXBhLCAtc3R1ZHlfbmFtZSkNCiAgc2VsZWN0KA0KICAgIHJlZ2lvbl92MiwgY291bnRyeSwgY2hhbm5lbCwgdGFjdGljLA0KICAgICMgdHJlYXRtZW50X3VzZXJfY291bnQ6Y29udHJvbCwNCiAgICBjb3N0X3NwZW50X29uX2V4cG9zZWRfZ3JvdXA6YWJzb2x1dGVfbGlmdA0KICApDQoNCmlzb19zbWJiIDwtIGlzb2xhdGlvbkZvcmVzdCRuZXcoc2FtcGxlX3NpemUgPSBucm93KGRmX3Rlc3QpLCBudW1fdHJlZXMgPSAxMDAwMCwgc2VlZCA9IDExNTIpDQoNCmlzb19zbWJiJGZpdChkZl90ZXN0KQ0KDQpzY29yZXNfdHJhaW4gPC0gZGZfdGVzdCAlPiUNCiAgaXNvX3NtYmIkcHJlZGljdCgpICU+JQ0KICBhcnJhbmdlKGRlc2MoYW5vbWFseV9zY29yZSkpDQoNCkZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3NtYmJfcHJlMiA8LQ0KICBGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9zbWJiX3ByZSAlPiUNCiAgbGVmdF9qb2luKHNjb3Jlc190cmFpbiwgYnkgPSBjKCJpZDIiID0gImlkIikpICU+JSANCiAgZmlsdGVyKGF2ZXJhZ2VfZGVwdGggPiA0KQ0KDQpGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9zbWJiIDwtDQogIEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3NtYmJfcHJlMiAlPiUNCiAgbmFtZWRfZ3JvdXBfc3BsaXQoY2hhbm5lbCkNCmBgYA0KDQojIyMjIFJ1biBNb2RlbA0KDQpgYGB7ciwgd2FybmluZyA9IGZhbHNlfQ0KZml0c19ub25fc2VhcmNoX3NtYmIgPC0gbW9kZWxfd3JhcHBlcl9mdW5jdGlvbihkZiA9IEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3NtYmIscG9seV9pbmQgPSAwKQ0KDQpiZXN0X2luZF9ub25fc2VhcmNoX3NtYmIgPC0gDQogIGxhcHBseSgxOmxlbmd0aChGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9zbWJiKSwgYmVzdF9pbmRfZnVuY3Rpb24sZGYgPSBmaXRzX25vbl9zZWFyY2hfc21iYiwNCiAgICAgICAgIGRmMiA9IEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3NtYmIpIA0KDQpjb2VmX25vbl9zZWFyY2hfc21iYiA8LSBiZXN0X2luZF9ub25fc2VhcmNoX3NtYmIgJT4lIGJpbmRfcm93cyAjbWFrZSBhIG1hdHJpeCBvZiBhbGwgY29lZnMNCg0KYmVzdF9maXRfbm9uX3NlYXJjaF9zbWJiIDwtIGJlc3RfaW5kX25vbl9zZWFyY2hfc21iYiAlPiUNCiAgc2V0X25hbWVzKG5hbWVzX2Z1bmN0aW9uKEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3NtYmJfcHJlLCBjaGFubmVsKSkgIA0KYGBgDQoNCiMjIyMgQ3JlYXRlIEdyYXBoIE9iamVjdA0KDQpgYGB7cn0NCmdyYXBoX2xpc3Rfc21iYiA8LSBsYXBwbHkoMTpsZW5ndGgoYmVzdF9maXRfbm9uX3NlYXJjaF9zbWJiKSwgZ3JhcGhpbmdfZnVuY3Rpb240LCBkZjEgPSBiZXN0X2ZpdF9ub25fc2VhcmNoX3NtYmIsIGRmMiA9IEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX3NtYmIpDQpgYGANCg0KDQpgYGB7cn0NCmVuZF90aW1lIDwtIFN5cy50aW1lKCkNCg0KdGltZV9zbWJiID0gZW5kX3RpbWUgLSBzdGFydF90aW1lDQpgYGANCg0KDQojIyBGdW5jdGlvbiB0byByZWZyZXNoIGFsbCBncmFwaHMNCg0KYGBge3J9DQojIyBSZW1vdmUgdHdvIHlvdXR1YmUgc3R1ZGllcyBmcm9tIG9yaWdpbmFsLCBhZGQgU01CIEVEQQ0KDQojIyBmb3IgbG9vcCBvZiBhbGwgZ3JhcGggb2JqZWN0cw0KYGBgDQoNCiMjIEV4cG9ydCBhbGwgZ3JhcGggbGlzdHMNCg0KYGBge3J9DQpncmFwaF9uYW1lcyA8LSBtZ2V0KGxzKHBhdCA9ICdncmFwaF9saXN0XycpKQ0KICAgDQpkZl9uYW1lcyA8LSBtZ2V0KHNldGRpZmYobHMocGF0dGVybiA9ICdGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV8nKSwgbHMocGF0dGVybiA9ICJwcmUiKSkpDQoNCnJtKEZpbmFsX0NMU18yMDIyX1N0dWR5X0xpc3RfTm9uX1NlYXJjaF9tb2RlbF9maWxlX0Nocm9tZSxGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9DbG91ZCxGaW5hbF9DTFNfMjAyMl9TdHVkeV9MaXN0X05vbl9TZWFyY2hfbW9kZWxfZmlsZV9Zb3VUdWJlKQ0KDQpsYXBwbHkoMTpsZW5ndGgoZ3JhcGhfbmFtZXMpLA0KICAgICAgZnVuY3Rpb24oaikgew0KbGFwcGx5KDE6bGVuZ3RoKGRmX25hbWVzW1tqXV0pLGV4cG9ydF9ycGxvdHNfZnVuY3Rpb24yLHN0YXJ0aW5nX25hbWUgPSAiTm9uX1NlYXJjaF8iLGZvbGRlcl9uYW1lID0gZm9sZGVyX25hbWUsZGZfbGlzdCA9IGRmX25hbWVzW1tqXV0sZ3JhcGhpbmdfbGlzdCA9IGdyYXBoX25hbWVzW2pdW1sxXV0pDQogICAgICB9DQogICAgICAgKQ0KYGBgDQoNCiMjIEdyaWQgb2YgYWxsIFJlc3BvbnNlIEN1cnZlcw0KDQpbKlN1YiBQbG90IERvY3VtZW50YXRpb24qXShodHRwczovL3Bsb3RseS5jb20vci9zdWJwbG90cy8pDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PSAxNSwgZWNobz1GQUxTRSxtZXNzYWdlPUZBTFNFLCB3YXJuaW5nID0gRkFMU0V9DQoNCmxhcHBseSgxOmxlbmd0aChncmFwaF9uYW1lcyksDQpmdW5jdGlvbihpKXsNCiAgc3VicGxvdChncmFwaF9uYW1lc1tpXVtbMV1dLCBucm93cyA9IGxlbmd0aChncmFwaF9uYW1lc1tpXVtbMV1dKSkNCn0NCikNCg0KDQpsYXBwbHkoMTpsZW5ndGgoZ3JhcGhfbmFtZXMpLA0KZnVuY3Rpb24oaSl7DQojcDEgPSBncmFwaF9uYW1lc1tpXVtbMV1dDQpkby5jYWxsKGdyaWQuYXJyYW5nZSxncmFwaF9uYW1lc1tpXVtbMV1dKQ0KI3JldHVybihncmlkLmFycmFuZ2UoZ3JvYnMgPSBwMSkpDQp9DQopDQoNCmBgYA0KDQojIyBDb2VmIE1hdHJpeA0KDQpgYGB7cn0NCmNvZWYuMl9tYXRyaXggPC0gbWdldCgobHMocGF0ID0gJ2NvZWZfJykpKQ0KDQpjb2VmLjJfbWF0cml4ICU+JSAgYmluZF9yb3dzKCkNCg0KDQpgYGANCg0KIyMgR3JhcGhzIHdpdGggQW5vbWFseSBTY29yZXMNCg0KYGBge3J9DQpncmFwaF9saXN0LmZpIDwtIGxhcHBseSgxOmxlbmd0aChiZXN0X2ZpdF9ub25fc2VhcmNoX2ZpKSwgZ3JhcGhpbmdfZnVuY3Rpb240X3dfYW5vbSwgZGYxID0gYmVzdF9maXRfbm9uX3NlYXJjaF9maSwgZGYyID0gRmluYWxfQ0xTXzIwMjJfU3R1ZHlfTGlzdF9Ob25fU2VhcmNoX21vZGVsX2ZpbGVfZmkpDQoNCiMjIyBBZGQgR0cgVGV4dCBSZXBlbA0KZ2dwbG90bHkoZ3JhcGhfbGlzdC5maVtbM11dKQ0KDQpgYGANCg0KIyBDcmVhdGUgYWxsIFJlc3BvbnNlIEN1cnZlcyAtIFJMTQ0KDQpgYGB7ciwgd2FybmluZyA9IEZBTFNFfQ0KDQoNCg0KZml0cy5ub24uc2VhcmNoLlJMTSA8LSBsYXBwbHkoDQogIDE6bGVuZ3RoKGRmX25hbWVzKSwNCiAgZnVuY3Rpb24oaSkgew0KICAgIG1vZGVsX3dyYXBwZXJfZnVuY3Rpb24yKGRmID0gZGZfbmFtZXNbaV0pDQogIH0NCikNCg0KDQoNCg0KDQpgYGANCg0KDQoNCmBgYHtyfQ0KDQoNCg0Kcm0oZ3JpZCxjb3N0X3AsY29zdCxyZXNwb25zZSxkYXRhLHBvd2VyLHksZGF0YTIsbW9kLGZpdHMubm9uLnNlYXJjaC5jaHJvbWVfUkxNKQ0KDQoNCg0KDQpgYGANCg0KDQoNCg0KDQoNCg==